<?php

namespace app\amqp\producer;

use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Wire\AMQPTable;

/**
 * 用死信队列模拟消息延迟消费
 */
class DelayProducer
{
    public function publish(string $data, string $routingKey, string $queueName) :void
    {
        $amqpConfig = config('amqp');

        $conn = new AMQPStreamConnection(
            host: $amqpConfig['host'],
            port: $amqpConfig['port'],
            user: $amqpConfig['user'],
            password: $amqpConfig['password'],
            vhost: $amqpConfig['vhost']
        );
        $channel = $conn->channel();

        // 创建正常的交换机和队列
        $channel->exchange_declare(
            exchange: $amqpConfig['exchange'],
            type: $amqpConfig['exchange_type'],
            passive: false,
            durable: true,
            auto_delete: false,
        );
        // 创建死信交换机和队列
        $deadLetterExchange = 'sms_delay_exchange';
        $deadLetterQueue = 'sms_delay_queue';
        $deadLetterRoutingKey = 'sms_delay_queue';
        $channel->exchange_declare(
            exchange: $deadLetterExchange,
            type: $amqpConfig['exchange_type'],
            passive: false,
            durable: true,
            auto_delete: false,
        );

        // 设置死信队列相关参数
        $args = new AMQPTable();
        // 设置延迟过期时间为10秒
        $args->set('x-message-ttl', 10000);
        // 设置死信交换器
        $args->set('x-dead-letter-exchange', $deadLetterExchange);
        // 设置死信路由键
        $args->set('x-dead-letter-routing-key', $deadLetterRoutingKey);
        // 声明死信队列
        $channel->queue_declare(
            queue: $deadLetterQueue,
            passive: false,
            durable: true,
            exclusive: false,
            auto_delete: false
        );
        // 声明队列，作为普通队列，同时将死信队列相关参数传入
        $channel->queue_declare(
            queue: $queueName,
            passive: false,
            durable: true,
            exclusive: false,
            auto_delete: false,
            arguments: $args
        );

        // 将死信队列与死信交换机绑定，同时指定死信路由键
        $channel->queue_bind(
            queue: $deadLetterQueue,
            exchange: $deadLetterExchange,
            routing_key: $deadLetterRoutingKey
        );
        // 将普通队列与普通交换机绑定
        $channel->queue_bind(
            queue: $queueName,
            exchange: $amqpConfig['exchange'],
            routing_key: $routingKey
        );

        $message = new AMQPMessage(
            body: $data,
            properties: ['content_type' => 'application/json', 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT]
        );

        $channel->basic_publish($message, $amqpConfig['exchange'], $routingKey);

        $channel->close();
        $conn->close();
    }
}
